%{
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "y.tab.h"
#include "utils.h"

#define I 0
#define F 1
#define S 2
#define B 3
#define C 4
#define U -1
  
  FILE *f = NULL;
  
  struct table symboles;
  struct table types;
  struct table locale;
  
  int inClass = 0;
  int inFunction = 0;
  int inBloc = 0;
  
  char *classe = NULL;
  char *fct = NULL;

  int nb_ligne=1;
  int PLUS[4][4];
  int MINUS[4][4];
  int MUL[4][4];
  int DIV[4][4];
  
  void init(int tab[4][4]) {
    int i=0;int j=0;
    for(i=0;i<4;i++)
      for(j=0;j<4;j++)
	tab[i][j]=U;
    
  }
  
  void init_tab(){
    
    init(PLUS);
    PLUS[I][I]=I;
    PLUS[I][F]=F;
    PLUS[F][I]=F;
    PLUS[F][F]=F;
        
    init(MINUS);
    MINUS[I][I]=I;
    MINUS[I][F]=F;
    MINUS[F][I]=F;
    MINUS[F][F]=F;
    
    init(MUL);
    MUL[I][I]=I;
    MUL[I][F]=F;
    MUL[F][I]=F;
    MUL[F][F]=F;
    
    init(DIV);
    DIV[I][I]=F;
    DIV[I][F]=F;
    DIV[F][I]=F;
    DIV[F][F]=F;

  }
  int translate(char *type){
    if(strcmp(type, "INT") == 0)
      return I;
    else if(strcmp(type, "FLOAT") == 0)
      return F;
    else if(strcmp(type, "STRING") == 0)
      return S;
    else if(strcmp(type, "BOOL") == 0)
      return B;
    return C;

  }

  char tmp[100];  
  int new_reg (){
    static int n =0;
    return ++n;
  }
  
  int newIf (){
    static int a =0;
    return ++a;
  }
  
  int newWhile(){
    static int w = 0;
    return ++w;
  }
  
  void print_begin() {
    fprintf(f,"%s","@str = constant [ 7 x i8 ] c\"=> %d\\0A\\00\"\n");
    fprintf(f,"%s","declare i32 @printf(i8*, ...)\n");
    fprintf(f,"%s","define i32 @main() {\n");
  }
  
  void print_end() {
    fprintf(f,"%s","\n}\n");
    
  }

  

  %}

//definit le type de yylval
%union{
  int i;
  char *s;
  float f;
  int bool;

    
  struct codes {
    char *id;
    int reg;
    char *type;
    char *code;
      
  }G ;
 }

%token NEW AND OR CLASS IF THEN ELSE END WHILE DO DEF LEQ GEQ FOR TO RETURN IN NEQ 
%token <f> FLOAT
%token <s> STRING ID CLASSCONST 
%token <i> INT
%left '*' 
%left '/'
%left '+' '-'
%left '<' '>' LEQ GEQ EQ
%left AND OR

%type <s> id classConst
%type <G> primary additive_expr multiplicative_expr comp_expr expr lhs stmts stmt topstmts topstmt

%%

program		:  topstmts opt_terms{
  if($1.code != NULL){
    fprintf(f, "%s",$1.code); 
    printf("FINAL CODE \n%s\n",$1.code);
  }
 }
;
topstmts        : {} 
| topstmt {$$ = $1;}
| topstmts terms topstmt {
  size_t t=sizeof(char*)+500;
  $$.code=malloc(t);
  snprintf($$.code,t,"%s%s",$1.code,$3.code);
 }
;




topstmt	        : CLASS beginClass classConst term stmts term END endClass{ 
  
 }


| stmt {$$ = $1;}
;

classConst:  CLASSCONST {
  $$ = $1; 
  classe = $1;  
  if(find_node($1, &types)== NULL)
    add_class($1, &types, 4, NULL);
 } 
| CLASSCONST '<' CLASSCONST{
  $$ = $1;
  classe = $1;
  if(find_node($3, &types) == NULL){
    printf("SuperClass %s non defined\n",$3);
    exit(1);
  }
  
  if(find_node($1, &types)== NULL)
    add_class($1, &types, 4, $3); 
  }




;
beginClass : {inClass = 1;}
;

endClass : {inClass = 0;}
;

stmts	        : /* none */{}  
| stmt {
  $$=$1;}
| stmts terms stmt {
  size_t t=sizeof(char*)+500;
  $$.code=malloc(t);
  snprintf($$.code,t,"%s%s",$1.code,$3.code);
  

 }
;

stmt		: IF beginBloc expr THEN stmts terms END endBloc{
  if ( strcmp($3.type, "BOOL")!= 0){
    printf("Ligne : %d Erreur sémantique: Utilisation d'une expression non booleene",nb_ligne);
    exit(1);
  }
  $$.reg=new_reg();
  size_t t=sizeof(char*)+200;
  $$.code=malloc(t);
  int i=newIf();
  snprintf($$.code,t,"%s\nbr i1 %%t%d, label %%if%d, label %%nif%d \nif%d:\n%snif%d:\n",$3.code,$3.reg,i,i,i,$5.code,i);
 }

| IF beginBloc expr THEN stmts terms ELSE stmts terms END endBloc { 
  if (strcmp($3.type, "BOOL") != 0){
    printf("Ligne : %d Erreur sémantique utilisation d'une expression non booleene",nb_ligne);
    exit(1);
  }
  size_t t=sizeof(char*)+4000;
  $$.code=malloc(t);
  $$.reg=new_reg();
  int i=newIf();
  snprintf($$.code,t,"%s\nbr i1 %%t%d, label %%if%d, label %%nif%d \nif%d:\n%sbr label %%end%d:\nnif%d:\n%sbr label %%end%d:\nend%d:\n",
	   $3.code,$3.reg,i,i,i,$5.code,i,i,$8.code,i,i);
		  
 }


| FOR beginBloc ID IN expr TO expr term stmts terms END endBloc{  if(strcmp($5.type,$7.type)!= 0){
     printf("Expressions not of the same type in line %d\n",nb_ligne);
     exit(1);
   }
   size_t t=sizeof(char*)+4000;
   $$.code=malloc(t);
   int tmp = newWhile();
   
   if(find_node($3, &symboles) == NULL){
     switch(translate($5.type)){
       
     case I:
       snprintf($$.code,t,"%%%s = alloca i32\nstore i32 %%t%d,i32* %%%s\n",$3,new_reg(),$3);
       add_var($3, "INT", &symboles, &types, NULL);
       break;
     default:
       printf("Error type Expression in bloc for in line %d\n",nb_ligne);
       exit(1);
     }
   }

   else{
     if(!check_type($3, $5.type, &symboles)){
       printf("%s Variable not of type expression in line %d\n",$5.type, nb_ligne);
       exit(1);
       
     }
     
   
   }
   snprintf($$.code,t,"%sbr label %%entry%d\nentry%d:\n%s%sbr label %%start%d\nstart%d:\n%%%s = phi i32 [%%t%d,%%entry%d],[%%nextvar,%%start%d]\n%s%%nextvar%d = add i32 %%%s,1\n%%cmp%d = icmp ule i32 %%%s,%%t%d\nbr i1 %%cmp%d,label %%start%d,label %%end%d\nend%d:\n",$$.code,tmp,tmp,$5.code,$7.code,tmp,tmp,$3,$5.reg,tmp,tmp,$9.code,tmp,$3,tmp,$3,$7.reg,tmp,tmp,tmp,tmp);
     
   debug_symb(&symboles);
   
 }
   
| WHILE beginBloc expr DO term stmts terms END endBloc{ 
  if (strcmp($3.type, "BOOL")!=0){
    printf("Ligne : %d Erreur sémantique utilisation d'une expression non booleene",nb_ligne);
    exit(1);
  }
  size_t t=sizeof(char*)+4000;
  $$.code=malloc(t);
  snprintf($$.code,t,"br label %%entry\nentry:\n%sbr i1 %%t%d,label %%start,label %%end\nstart:\n%sbr label %%entry\nend:\n",$3.code,$3.reg,$6.code);
		  
 }
                  
| lhs '=' expr {
  
  if($3.type == NULL){
      printf("Unkown Type of Expression in line %d\n",nb_ligne);
      exit(1);
  }
  if(find_node($1.id, &symboles) != NULL){
    if(!check_type($1.id, $3.type, &symboles)){
      printf("Non compatible expression for variable %s in line %d\n",$1.id, nb_ligne);
      exit(1);
      
    }
    else{
      size_t t=sizeof(char*)+200;
    $$.code=malloc(t);
		  
    switch (translate($3.type)){
		      
    case(S):
      snprintf($$.code,t,"%sstore i8 %%t%d, %%t%s\n",$3.code,$3.reg,$1.id);
      break;
    case(I):
      snprintf($$.code,t,"%sstore i32 %%t%d,i32* %%%s\n",$3.code,$3.reg,$1.id);
      break;
    case(F):
      snprintf($$.code,t,"%sstore float %%t%d,float* %%%s\n",$3.code,$3.reg,$1.id);
      break;
    case(B):
      snprintf($$.code,t,"%sstore i1 %%t%d,i1* %%%s\n",$3.code,$3.reg,$1.id);
      break;
		      
    case(C):
      break;
    default:
      printf(" Ligne %d: Erreur sémantique, Expression incorrecte à l'affectation \n",nb_ligne);
      exit(1);
    }
      
    }
    
    		    
  }
  
  
  else{
    add_var($1.id, $3.type, &symboles, &types, NULL);
    size_t t=sizeof(char*)+200;
    $$.code=malloc(t);
		  
    switch (translate($3.type)){
		      
    case(S):
      snprintf($$.code,t,"%sstore i8 %%t%d, %%t%s\n",$3.code,$3.reg,$1.id);
      break;
    case(I):
      snprintf($$.code,t,"%s%%%s = alloca i32\nstore i32 %%t%d,i32* %%%s\n",$3.code,$1.id,$3.reg,$1.id);
      break;
    case(F):
      snprintf($$.code,t,"%s%%%s = alloca float\nstore float %%t%d,float* %%%s\n",$3.code,$1.id,$3.reg,$1.id);
      break;
    case(B):
      snprintf($$.code,t,"%s%%%s = alloca i1\nstore i1 %%t%d,i1* %%%s\n",$3.code,$1.id,$3.reg,$1.id);
      break;
		      
    case(C):
      break;
    default:
      printf(" Ligne %d: Erreur sémantique, Expression incorrecte à l'affectation \n",nb_ligne);
      exit(1);
    }
    
    
    
  }
  }
  
| RETURN expr {}

  
| DEF  id beginFunction opt_params term stmts terms END endFunction 
{
  if(inClass)
    add_function($2, 0, NULL, NULL, classe, &types, &symboles);

  else
    add_function($2, 0, NULL, NULL, NULL, &types, &symboles);
}

| ID '.' primary {
  if(find_node($1, &symboles) == NULL){
    printf("Object %s non constructed\n",$1);
    exit(1);
  }

  if( !check_object_calling($1, $3.id, &symboles, 0, NULL)){
    printf("Error in calling methodes %s on object %s\n",$3.id, $1);
    exit(1);

  }
  else
    printf("Call method %s succeded on object %s",$3.id, $1);
		    
  }
		
| ID '(' exprs ')' {
  $$.id=$1;
		  
  }


; 

id : ID {$$ = $1; fct = $1;} 
;

beginBloc: {inBloc = 1;}
;
endBloc : {inBloc = 0;}
;
beginFunction : {inFunction = 1;}
;
endFunction : {inFunction = 0;}
;
opt_params      : /* none */ 
| '(' ')' 
| '(' params ')' 
;


params          : ID ',' params 
| ID
; 


lhs             : ID {
  if(find_node($1, &symboles) != NULL){
    $$.type = return_type($1, &symboles);
    $$.id=$1;
  }
  
  
 }

                  
;                

                
exprs           : exprs ',' expr
| expr
;
primary         : /*none*/ {;} 
| lhs {
  $$.reg=new_reg();
  $$.id=$1.id;
  $$.type=$1.type;
  size_t t=sizeof(char*)+sizeof(float)+100;
  $$.code=(char*)malloc(t);
  switch(translate($1.type)){
  case I:
    snprintf($$.code,t,"%%t%d = load i32* %%%s\n",$$.reg,$1.id);
    break;
  case S:
    snprintf($$.code,t,"%%t%d = load i8* %%%s\n",$$.reg,$1.id);
    break;
  case F:
    snprintf($$.code,t,"%%t%d = load float %%%s\n",$$.reg,$1.id);
    break;
  case B:
    snprintf($$.code,t,"%%t%d = load i1* %%%s\n",$$.reg,$1.id);
    break;
  case C:
    break;
  default:
    printf("Eroor loading variable %s in line %d",$1.id,nb_ligne);
    
  
  }
		  
 }

| STRING {
  $$.reg=new_reg();
  $$.code=(char *)malloc(sizeof(char));
  $$.type = malloc(sizeof(char)*strlen("STRING"));
  strcpy($$.type, "STRING");
  }

| FLOAT {
  $$.reg = new_reg();
  $$.type = malloc(sizeof(char)*strlen("FLOAT"));
  strcpy($$.type, "FLOAT");
  size_t t=sizeof(char*)+sizeof(float)+100;
  $$.code=(char*)malloc(t);
  snprintf($$.code,t,"%%t%d = fadd float %f,0.\n",$$.reg,$1);
  }

| INT {
  $$.reg = new_reg();
  $$.type = malloc(sizeof(char)*strlen("INT"));
  strcpy($$.type, "INT");
  size_t t=sizeof(char*)+sizeof(float)+100;
  $$.code=(char *)malloc(t);
  snprintf($$.code,t,"%%t%d = add i32 %d,0\n",$$.reg,$1);
  }

| '(' expr ')' {
		  
  $$.type=$2.type;
  }
;
expr            : expr AND comp_expr {
  if((strcmp($1.type, "BOOL")== 0)&&(strcmp($3.type, "BOOL")==0)) 
    $$.type= $1.type; 
  else{
    printf(" Ligne %d: Erreur sémantique utilisation de AND avec une expressio non booleene\n",nb_ligne);
    exit(1);
  }
  size_t t=sizeof(char*)+1000;
  $$.code=(char*)malloc(t);
  $$.reg=new_reg();
  snprintf($$.code,t,"%s%s%%t%d = and i1 %%t%d,%%t%d",$1.code,$3.code,$$.reg,$1.reg,$3.reg);
 }

| expr OR comp_expr {
  if((strcmp($1.type, "BOOL")==0)&&(strcmp($3.type, "BOOL")==0)) 
    $$.type=$1.type; 
  else{
    printf(" Ligne %d: Erreur sémantique utilisation de OR avec une expression non booleene\n",nb_ligne);
    exit(1);
  }
  size_t t=sizeof(char*)+1000;
  $$.code=(char*)malloc(t);
  $$.reg=new_reg();
  snprintf($$.code,t,"%s%s%%t%d = or i1 %%t%d,%%t%d",$1.code,$3.code,$$.reg,$1.reg,$3.reg);
 }

| comp_expr {$$=$1;}

| CLASSCONST '.' NEW opt_params {
  if(find_node($1, &types) == NULL){
    printf("Class %s non declared\n",$1);
    exit(1);
		      
  }
		  
  $$.type= find_node($1, &types)->id;
  }
| ID '.' primary {
  if(find_node($1, &symboles) == NULL){
    printf("Object %s non constructed\n",$1);
    exit(1);
  }

  if( !check_object_calling($1, $3.id, &symboles, 0, NULL)){
    printf("Error in calling methodes %s on object %s\n",$3.id, $1);
    exit(1);

  }
  else
    printf("Call method %s succeded on object %s\n",$3.id, $1);
		    
  }
		
| ID '(' exprs ')' {
  $$.id=$1;
		  
  }


;
comp_expr       : additive_expr '<' additive_expr {
  if(strcmp($1.type,$3.type) != 0){
    printf("Ligne %d: Erreur, Types incompatibles lors de la comparaison\n",nb_ligne);
    exit(1);
  }
  $$.reg = new_reg();
  $$.type= (char *)malloc(sizeof(char)*strlen("BOOL"));
  strcpy($$.type, "BOOL");
  size_t t=sizeof(char*)+200;
  $$.code=(char*)malloc(t);
  
  
  switch(translate($1.type)){
  case(I):
    snprintf($$.code,t,"%s%s%%t%d = icmp ult i32 %%t%d, %%t%d\n",$1.code,$3.code,$$.reg,$1.reg,$3.reg);
    break;
  case(F):
    snprintf($$.code,t,"%s%s%%t%d = fcmp ult float %%t%d, %%t%d\n",$1.code,$3.code,$$.reg,$1.reg,$3.reg);
    break;
  default:
    printf("Ligne %d: Erreur, Types incompatibles lors de la comparaison\n",nb_ligne);
    exit(1);
  }
  
  
 } 
| additive_expr '>' additive_expr {
  if(strcmp($1.type,$3.type)!= 0){
    printf("Ligne %d: Erreur, Types incompatibles lors de la comparaison\n",nb_ligne);
    exit(1);
  }
  $$.reg = new_reg();
  $$.type= (char *)malloc(sizeof(char)*strlen("BOOL"));
  strcpy($$.type, "BOOL");
  size_t t=sizeof(char*)+200;
  $$.code=(char*)malloc(t);
  switch(translate($1.type)){
  case(I):
    snprintf($$.code,t,"%s%s%%t%d = icmp ugt i32 %%t%d, %%t%d\n",$1.code,$3.code,$$.reg,$1.reg,$3.reg);
    break;
  case(F):
    snprintf($$.code,t,"%s%s%%t%d = fcmp ugt float %%t%d, %%t%d\n",$1.code,$3.code,$$.reg,$1.reg,$3.reg);
    break;
  default:
    printf("Ligne %d: Erreur, Types incompatibles lors de la comparaison\n",nb_ligne);
    exit(1);
  }
		   
		  
		  
  }
| additive_expr LEQ additive_expr {
  if(strcmp($1.type, $3.type) != 0){
    printf("Ligne %d: Erreur, Types incompatibles lors de la comparaison\n",nb_ligne);
    exit(1);
  }
  $$.reg = new_reg();
  $$.type= (char *)malloc(sizeof(char)*strlen("BOOL"));
  strcpy($$.type, "BOOL");
  size_t t=sizeof(char*)+200;
  $$.code=(char*)malloc(t);
  switch(translate($1.type)){
  case(I):
    snprintf($$.code,t,"%s%s%%t%d = icmp ule i32 %%t%d, %%t%d\n",$1.code,$3.code,$$.reg,$1.reg,$3.reg);
    break;
  case(F):
    snprintf($$.code,t,"%s%s%%t%d = fcmp ule float %%t%d, %%t%d\n",$1.code,$3.code,$$.reg,$1.reg,$3.reg);
    break;
  default:
    printf("Ligne %d: Erreur, Types incompatibles lors de la comparaison\n",nb_ligne);
    exit(1);
  }
		  
		  
 }
| additive_expr GEQ additive_expr {
  if(strcmp($1.type,$3.type)!= 0){
    printf("Ligne %d: Erreur, Types incompatibles lors de la comparaison\n",nb_ligne);
    exit(1);
  }
  $$.reg = new_reg();
  $$.type= (char *)malloc(sizeof(char)*strlen("BOOL"));
  strcpy($$.type, "BOOL");
  size_t t=sizeof(char*)+200;
  $$.code=(char*)malloc(t);
  switch(translate($1.type)){
  case(I):
    snprintf($$.code,t,"%s%s%%t%d = icmp uge i32 %%t%d, %%t%d\n",$1.code,$3.code,$$.reg,$1.reg,$3.reg);
    break;
  case(F):
    snprintf($$.code,t,"%s%s%%t%d = fcmp uge float %%t%d, %%t%d\n",$1.code,$3.code,$$.reg,$1.reg,$3.reg);
    break;
  default:
    printf("Ligne %d: Erreur, Types incompatibles lors de la comparaison\n",nb_ligne);
    exit(1);
  }
		  
 }
| additive_expr EQ additive_expr {
  if(strcmp($1.type,$3.type)!= 0){
    printf("Ligne %d: Erreur, Types incompatibles lors de la comparaison\n",nb_ligne);
    exit(1);
  }
  $$.reg = new_reg(); 
  $$.type= (char *)malloc(sizeof(char)*strlen("BOOL"));
  strcpy($$.type, "BOOL");
  size_t t=sizeof(char*)+200;
  $$.code=(char*)malloc(t);
  switch(translate($1.type)){
  case(I):
    snprintf($$.code,t,"%s%s%%t%d = icmp eq i32 %%t%d, %%t%d\n",$1.code,$3.code,$$.reg,$1.reg,$3.reg);
    break;
  case(F):
    snprintf($$.code,t,"%s%s%%t%d = fcmp eq float %%t%d, %%t%d\n",$1.code,$3.code,$$.reg,$1.reg,$3.reg);
    break;
  default:
    printf("Ligne %d: Erreur, Types incompatibles lors de la comparaison\n",nb_ligne);
    exit(1);
  }
		  
 }
| additive_expr NEQ additive_expr {
  if(strcmp($1.type,$3.type)!= 0){
    printf("Ligne %d: Erreur, Types incompatibles lors de la comparaison\n",nb_ligne);
    exit(1);
  }
  $$.reg = new_reg();
  $$.type= (char *)malloc(sizeof(char)*strlen("BOOL"));
  strcpy($$.type, "BOOL");
  size_t t=sizeof(char*)+200;
  $$.code=(char*)malloc(t);
  switch(translate($1.type)){
  case(I):
    snprintf($$.code,t,"%s%s%%t%d = icmp ne i32 %%t%d, %%t%d\n",$1.code,$3.code,$$.reg,$1.reg,$3.reg);
    break;
  case(F):
    snprintf($$.code,t,"%s%s%%t%d = fcmp ne float %%t%d, %%t%d\n",$1.code,$3.code,$$.reg,$1.reg,$3.reg);
    break;
  default:
    printf("Ligne %d: Erreur, Types incompatibles lors de la comparaison\n",nb_ligne);
    exit(1);
  }
		  
 }
| additive_expr {$$=$1;}
;
additive_expr   : multiplicative_expr {$$=$1;}

| additive_expr '+' multiplicative_expr {
  size_t t=sizeof(char*)+200;
  $$.code=(char*)malloc(t);
  char *tmp=(char*)malloc(t);
  switch(PLUS[translate($1.type)][translate($3.type)]){
  case(I):
    $$.reg=new_reg();
    snprintf($$.code,t,"%s%s%%t%d = add i32 %%t%d, %%t%d\n",$1.code,$3.code,$$.reg,$1.reg,$3.reg);
    break;
  case(F):
    if(translate($1.type)==I){
      sprintf(tmp,"%%t%d = sitofp i32 %%t%d to float\n",new_reg(),$1.reg);
      $$.reg=new_reg();
      snprintf($$.code,t,"%s%s%s%%t%d = fadd float %%t%d, %%t%d\n",$1.code,$3.code,tmp,$$.reg,$$.reg-1,$3.reg);
    }
    else if(translate($3.type)==I){
      sprintf(tmp,"%%t%d = sitofp i32 %%t%d to float\n",new_reg(),$3.reg);
      $$.reg=new_reg();
      snprintf($$.code,t,"%s%s%s%%t%d = fadd float %%t%d, %%t%d\n",$1.code,$3.code,tmp,$$.reg,$1.reg,$$.reg-1);
    }
    else{
      $$.reg=new_reg();
      snprintf($$.code,t,"%s%s%%t%d = fadd float %%t%d, %%t%d\n",$1.code,$3.code,$$.reg,$1.reg,$3.reg);
    }
    break;
  default:
    printf("Ligne %d: Erreur, Types incompatibles lors de l'addition\n",nb_ligne);
    exit(1);
  }
  (translate($1.type) <= translate($3.type))? ($$.type = $3.type):($$.type = $1.type);
		  
  }
| additive_expr '-' multiplicative_expr {
  size_t t=sizeof(char*)+200;
  $$.code=(char*)malloc(t);
  char *tmp=(char*)malloc(t);
  switch(MINUS[translate($1.type)][translate($3.type)]){
  case(I):
    $$.reg=new_reg();
    snprintf($$.code,t,"%s%s%%t%d = sub i32 %%t%d, %%t%d\n",$1.code,$3.code,$$.reg,$1.reg,$3.reg);
    break;
  case(F):
    if(translate($1.type)==I){
      sprintf(tmp,"%%t%d = sitofp i32 %%t%d to float\n",new_reg(),$1.reg);
      $$.reg=new_reg();
      snprintf($$.code,t,"%s%s%s%%t%d = fsub float %%t%d, %%t%d\n",$1.code,$3.code,tmp,$$.reg,$$.reg-1,$3.reg);
    }
    else if(translate($3.type)==I){
      sprintf(tmp,"%%t%d = sitofp i32 %%t%d to float\n",new_reg(),$3.reg);
      $$.reg=new_reg();
      snprintf($$.code,t,"%s%s%s%%t%d = fsub float %%t%d, %%t%d\n",$1.code,$3.code,tmp,$$.reg,$1.reg,$$.reg-1);
    }
    else{
      $$.reg=new_reg();
      snprintf($$.code,t,"%s%s%%t%d = fsub float %%t%d, %%t%d\n",$1.code,$3.code,$$.reg,$1.reg,$3.reg);
    }
    break;
  default:
    printf("Ligne %d: Erreur soustraction: types incompatibles\n",nb_ligne);
    exit(1);
  }
  (translate($1.type) <= translate($3.type))? ($$.type = $3.type):($$.type = $3.type);
		  
  }
;
multiplicative_expr : multiplicative_expr '*' primary {
  size_t t=sizeof(char*)+200;
  $$.code=(char*)malloc(t);
  char *tmp=(char*)malloc(t);
  switch(MUL[translate($1.type)][translate($3.type)]){
  case(I):
    $$.reg=new_reg();
    snprintf($$.code,t,"%s%s%%t%d = mul i32 %%t%d, %%t%d\n",$1.code,$3.code,$$.reg,$1.reg,$3.reg);
    break;
  case(F):
    if(translate($1.type)==I){
      sprintf(tmp,"%%t%d = sitofp i32 %%t%d to float\n",new_reg(),$1.reg);
      $$.reg=new_reg();
      snprintf($$.code,t,"%s%s%s%%t%d = fmul float %%t%d, %%t%d\n",$1.code,$3.code,tmp,$$.reg,$$.reg-1,$3.reg);
    }
    else if(translate($3.type)==I){
      sprintf(tmp,"%%t%d = sitofp i32 %%t%d to float\n",new_reg(),$3.reg);
      $$.reg=new_reg();
      snprintf($$.code,t,"%s%s%s%%t%d = fmul float %%t%d, %%t%d\n",$1.code,$3.code,tmp,$$.reg,$1.reg,$$.reg-1);
    }
    else{
      $$.reg=new_reg();
      snprintf($$.code,t,"%s%s%%t%d = fmul float %%t%d, %%t%d\n",$1.code,$3.code,$$.reg,$1.reg,$3.reg);
    }
    break;
  default:
    printf("Ligne %d: Erreur, Types incompatibles lors de la multiplication\n",nb_ligne);
    exit(1);
  }
  (translate($1.type) <= translate($3.type))? ($$.type = $3.type):($$.type = $1.type);
		       
		       
 }
| multiplicative_expr '/' primary {
  if(translate($1.type) >2 || translate($3.type) >2){
    printf("Erreur division, types incompatibles\n");
    exit(1);
  }
  size_t t=sizeof(char*)+200;
  $$.code=(char*)malloc(t);
  char *tmp=(char*)malloc(t);
  if(translate($1.type)==I && translate($3.type)==I){
    int r1=new_reg();
    int r2=new_reg();
    sprintf(tmp,"%%t%d = sitofp i32 %%t%d to float\n%%t%d = sitofp i32 %%t%d to float\n",r1,$1.reg,r2,$3.reg);
    $$.reg=new_reg();
    snprintf($$.code,t,"%s%s%s%%t%d = fdiv float %%t%d, %%t%d\n",$1.code,$3.code,tmp,$$.reg,$$.reg-2,$$.reg-1);
  }
  else if(translate($1.type)==I){
    sprintf(tmp,"%%t%d = sitofp i32 %%t%d to float\n",new_reg(),$1.reg);
    $$.reg=new_reg();
    snprintf($$.code,t,"%s%s%s%%t%d = fdiv float %%t%d, %%t%d\n",$1.code,$3.code,tmp,$$.reg,$$.reg-1,$3.reg);
  }
  else if(translate($3.type)==I){
    sprintf(tmp,"%%t%d = sitofp i32 %%t%d to float\n",new_reg(),$3.reg);
    $$.reg=new_reg();
    snprintf($$.code,t,"%s%s%s%%t%d = fdiv float %%t%d, %%t%d\n",$1.code,$3.code,tmp,$$.reg,$1.reg,$$.reg-1);
  }
  else{
    $$.reg=new_reg();
    snprintf($$.code,t,"%s%s%%t%d = fdiv float %%t%d, %%t%d\n",$1.code,$3.code,$$.reg,$1.reg,$3.reg);
  }
  (translate($1.type) <= translate($3.type))? ($$.type = $3.type):($$.type = $1.type);
		      
  }
| primary {$$ = $1;}
;
opt_terms	: /* none */
| terms
;

terms		: terms ';'
| terms '\n' {nb_ligne++;}
| ';'
| '\n'{nb_ligne++;}
;
term            : ';'
| '\n' {nb_ligne++;}
;
%%
int main() {
  
  init_table(&symboles);
  init_table(&types);
  init_table(&locale);
  add_class("INT", &types, 0, NULL);
  add_class("FLOAT", &types, 1, NULL);
  add_class("BOOL", &types, 2, NULL);
  add_class("STRING", &types, 3, NULL);
  nb_ligne = 1;
  f=fopen("result.ll","w+");
  print_begin();
  yyparse(); 
  print_end();
  fclose(f);
  debug_symb(&symboles);
  debug_type(&types);
  
  return 0;
}
